home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d20 / mxms_161.arc / MISC.C < prev    next >
C/C++ Source or Header  |  1991-08-04  |  38KB  |  1,345 lines

  1. /****************************************************************************/
  2. /*                                                                          */
  3. /*    Misc.c      :Miscellaneous routines for MaxMail                       */
  4. /*                                                                          */
  5. /****************************************************************************/
  6.  
  7. #include "MaxMail.h"
  8. #include <sys\timeb.h>
  9.  
  10. struct user_cfg uscfg;
  11. int do_reset;
  12. int CurColor;
  13. int Hollercount=0;
  14. int Bells;
  15.  
  16. extern int newuser;
  17. extern int FirstArc;
  18.  
  19. void _pascal signon()
  20. {
  21.    char *p;
  22.    struct stat fbuf;
  23.  
  24.    setcolor(TextAttr[HILITE_TEXT]);
  25.  
  26.    clearscreen();
  27.  
  28.    sprintf(temp,"Begin, v%2.2f",Version);
  29.    logit(temp,'+');
  30.    if (!newuser) 
  31.       sprintf(temp,"%s logging on",LastUser.name);
  32.    else sprintf(temp,"New User: %s logging on",LastUser.name);
  33.    logit(temp,':');
  34.  
  35.    strout("MaxMail - a MAXIMUS mail/message archiver utility by Craig Derouen\r\n");
  36.    sprintf(temp,"\t *** Version %2.2f ***\r\n",Version);
  37.    strout(temp);
  38.  
  39.    setcolor(TextAttr[STD_TEXT]);
  40.    strcpy(temp1,LastUser.name);
  41.    p = strtok(temp1," ");        /* Fetch 1st name only, shows how friendly we are */
  42.    if (USERCFG.calls) {
  43.       sprintf(temp,"\r\nWelcome back to MaxMail, %s.\r\n",p);
  44.       strout(temp);
  45.       sprintf(temp,"You have had %d previous successful downloads. Good luck!\r\n",USERCFG.packcount);
  46.       strout(temp);
  47.    }
  48.    else {
  49.       sprintf(temp,"\r\nWelcome to MaxMail, %s.\r\n",p);
  50.       strout(temp);
  51.   }
  52.  
  53. /* Now test filedate on Bulletin file. If it is newer than last logon
  54.    of user, display it. */
  55.  
  56.    if(stat(BullFile,&fbuf) == 0 && !newuser ) {        /* File does exist */
  57.       if ((fbuf.st_mtime >= USERCFG.lasttime ))    {    /* See if changed since last logon */
  58.          logit("User is viewing bulletin file",'#');
  59.          strout("\r\nBulletins:\r\n");
  60.          show_file(BullFile,TRUE);
  61.       }
  62.    }
  63. }
  64.  
  65. void _pascal menu(void)
  66. {
  67.    int choice;
  68.    int good,x;
  69.    unsigned msgs;
  70.    struct msgupd_st *msgupd;
  71.    time_t testtime;
  72.    time_t thistime;
  73.  
  74.    choice = TRUE;
  75.    PackDone = FALSE;
  76.    while (choice) {
  77.       if (USERCFG.msgfrmt == 1)
  78.          qwkinit();
  79.       msgs = get_msgcount();
  80.       if (msgs) {
  81.          setcolor(TextAttr[HILITE_TEXT]);
  82.          if (PackDone){
  83.             msgs = msgs < MaxMsgs ? msgs : MaxMsgs;
  84.             sprintf(temp,"\r\nYou have %u messages in %s. Select [T]ransmit to download\r\n",msgs,ArcFile);
  85.             strout(temp);
  86.             strout("or select [R]eset,[A]dd or [D]elete to scan more messages/areas\r\n");
  87.             setcolor(TextAttr[STD_TEXT]);
  88.             strout("\r\nSelect a choice\r\n");
  89.          }
  90.          else {
  91.             setcolor(TextAttr[HILITE_TEXT]);
  92.             sprintf(temp,"\r\nThere are %u new messages in areas:\r\n",msgs);
  93.             strout(temp);
  94.             setcolor(TextAttr[STD_TEXT]);
  95.             show_areas(TRUE);
  96.             if (msgs > MaxMsgs) {
  97.                setcolor(TextAttr[ATTN_TEXT]);
  98.                sprintf(temp,"\r\nSorry, but only %u new messages can be packed up during this run.\r\n",MaxMsgs);
  99.                strout(temp);
  100.                sprintf(temp,"MaxMail will pack up the first %u messages it finds.\r\n",MaxMsgs);
  101.                strout(temp);
  102.             }
  103.             setcolor(TextAttr[HILITE_TEXT]);
  104.             strout("\r\nPress ENTER to capture new messages, or select a choice\r\n");
  105.          }
  106.       }
  107.       else {
  108.          setcolor(TextAttr[HILITE_TEXT]);
  109.          strout("\r\n Sorry, but you have NO new messages to capture\r\n");
  110.          strout(" in the current message areas you have selected.\r\n");
  111.          setcolor(TextAttr[STD_TEXT]);
  112.          strout("\r\nSelect a choice\r\n");
  113.       }
  114.       setcolor(TextAttr[STD_TEXT]);
  115.       strout("-------------------------------------------------------\r\n");
  116.       setcolor(TextAttr[MENU_KEY]);
  117.       strout("[C]hange configuration   [L]ist configuration\r\n");
  118.       strout("[A]dd message areas      [D]elete message areas\r\n");
  119.       strout("[R]eset message pointers [S]can for new messages\r\n");
  120.       if (YellOn) {
  121.          strout("[V]ersion                [Y]ell for sysop\r\n");
  122.          if (!IsLocal) {
  123.             strout("[Q]uit back to Maximus");
  124.             if (Hangup)
  125.                strout("   [G]oodbye, hang up\r\n");
  126.             else strout("\r\n");
  127.          }
  128.          else strout("[Q]uit to DOS\r\n");
  129.       }
  130.       else {
  131.          if (!IsLocal) {
  132.             strout("[V]ersion                [Q]uit back to Maximus\r\n");
  133.             if (Hangup)
  134.                strout("[G]oodbye, hang up\r\n");
  135.          }
  136.          else strout("[V]ersion                [Q]uit to DOS\r\n");
  137.       }
  138.       if (HelpFile[0] != 0) {
  139.          setcolor(TextAttr[HILITE_TEXT]);
  140.          strout("[H]elp\r\n");
  141.       }
  142.       if (USERCFG.msgfrmt == 1) {
  143.          setcolor(TextAttr[HILITE_TEXT]);
  144.          strout("[U]pload REP packet\r\n");
  145.       }
  146.       if (PackDone) {
  147.          setcolor(TextAttr[HILITE_TEXT]);
  148.          strout("[T]ransmit archive\r\n");
  149.       }
  150.       if (LastUser.priv >= ASSTSYSOP) {
  151.          setcolor(TextAttr[STD_TEXT]);
  152.          strout("[Z]Sysop functions\r\n");
  153.       }
  154.       strout("\r\n");
  155.       good = FALSE;
  156.       while (!good) {
  157.          timeremain();
  158.          setcolor(TextAttr[PROMPT_TEXT]);
  159.          strout("Choice --> ");
  160.          ChatOk = TRUE;
  161.          x = chrin();
  162.          if (isalpha(x))
  163.             x &= 0x00df;        /* Force upper case, toupper() has side effects */
  164.          ChatOk = FALSE;
  165.          if(x == '\r')
  166.             x = 'S';
  167.          good = TRUE;
  168.          chrout((char) x);
  169.          strout("\r\n");
  170.          setcolor(TextAttr[STD_TEXT]);
  171.          switch (x) {
  172.             case 'A':
  173.                add_msgareas();
  174.                break;
  175.  
  176.             case 'C':
  177.                configmenu();
  178.                break;
  179.  
  180.             case 'D':
  181.                del_msgareas();
  182.                break;
  183.  
  184.             case 'G':
  185.                if (Hangup) {
  186.                   choice = FALSE;
  187.                   Hangup = 1;
  188.                }
  189.                break;
  190.  
  191.             case 'H':
  192.             case '?':
  193.                if (HelpFile[0]) {
  194.                   if (show_file(HelpFile,TRUE)) {
  195.                      setcolor(TextAttr[ATTN_TEXT]);
  196.                      strout("\r\nSorry, the help file is missing. Tell the sysop.\r\n");
  197.                      sprintf(temp,"User Helpfile %s is missing",HelpFile);
  198.                      logit(temp,'!');
  199.                      HelpFile[0] = 0;        /* Prevent it from being called again */
  200.                   }
  201.                }
  202.                break;
  203.  
  204.             case 'L':
  205.                list_config();
  206.                break;
  207.  
  208.             case 'Q':
  209.                choice = FALSE;
  210.                Hangup = 0;
  211.                if (!packer_del && PackDone) /* Kill any built archives */
  212.                   erase_arc();
  213.                break;
  214.  
  215.             case 'R':
  216.                edit_msgptrs();
  217.                break;
  218.  
  219.             case 'S':
  220.                if (msgs) {
  221.                /* Check last called date. Compare it to now and 24hour count */
  222.                   time(&thistime);
  223.                   testtime = thistime - USERCFG.lasttime;        /* How many seconds since last call? */
  224.                   if (testtime < (time_t) (3600 * 24) ) {        /* Seconds in 24 hours */
  225.                      if (!IsLocal && MaxDaily && LastUser.priv < ASSTSYSOP &&
  226.                         (USERCFG.dailycount >= (byte) MaxDaily)) { /* User can not scan */
  227.                         setcolor(TextAttr[ATTN_TEXT]);
  228.                         sprintf(temp,"\r\nSorry, %s, but you have already run MaxMail %d times today.\r\n",
  229.                            USERCFG.name,USERCFG.dailycount);
  230.                         strout(temp);
  231.                         sprintf(temp,"The sysop here only allows %d message runs from MaxMail daily.\r\n",MaxDaily);
  232.                         strout(temp);
  233.                         strout("Try running MaxMail again in 24 hours from now.\r\n");
  234.                      }
  235.                      else {
  236.                         if (scan_msgs() && totmsgs) {
  237.                            if(Packit()) {
  238.                               if (sendit()) {
  239.                                  if(packer_del)
  240.                                     PackDone = FALSE;
  241.                                  choice = FALSE;
  242.                               }
  243.                            }
  244.                         }
  245.                      }
  246.                   }
  247.                   else {
  248.                      USERCFG.dailycount = 0;        /* Reset it then */
  249.                      if (scan_msgs() && totmsgs) {
  250.                         if(Packit()) {
  251.                            if (sendit()) {
  252.                               PackDone = FALSE;
  253.                               choice = FALSE;
  254.                            }
  255.                         }
  256.                      }
  257.                   }
  258.                }
  259.                else good = FALSE;
  260.                break;
  261.  
  262.             case 'T':
  263.                if (PackDone) {
  264.                   if (sendit()) {
  265.                      PackDone = FALSE;
  266.                      choice = FALSE;
  267.                   }
  268.                }
  269.                else good = FALSE;
  270.                break;
  271.  
  272.             case 'U':
  273.                if (USERCFG.msgfrmt == 1) 
  274.                   getrep();
  275.                break;
  276.  
  277.             case 'V':
  278.                ShowVers();
  279.                break;
  280.  
  281.             case 'Y':
  282.                if (YellOn)
  283.                   Holler();
  284.                break;
  285.  
  286.             case 'Z':
  287.                if (LastUser.priv >= ASSTSYSOP) 
  288.                   Sys_menu();        /* We won't return from Sysop menu */
  289.                else good = FALSE;
  290.                break;
  291.  
  292.             case '!':        /* Redraw the full menu */
  293.                good = TRUE;
  294.                break;
  295.  
  296.             default:
  297.                good = FALSE;
  298.                break;
  299.          }
  300.       }
  301.    }
  302.    if (PackDone && packer_del) {        /* Pack file aborted */
  303.       if (LogMode == VERBOSE) logit("User aborted message pack",'~');
  304.       erase_arc();
  305.       msgupd = MSGUPD_1;
  306.       while (msgupd) {
  307.          msgupd->update = FALSE;
  308.          msgupd = msgupd->next;
  309.       }
  310.    }
  311.    return;
  312. }
  313.  
  314. void _pascal display_packers(void)
  315. {
  316.    int x,col;
  317.    struct packer_st *pack1;
  318.  
  319.    pack1 = PACKER_1;
  320.  
  321.    col = 0;
  322.    for (x = 0; x < totpackers; x++) {
  323.       sprintf(temp,"[%d]%s",x +1,pack1->packname);
  324.       while (strlen(temp) < 32) 
  325.          strcat(temp," ");
  326.       strout(temp);
  327.       if (col++) {
  328.          strout("\r\n");
  329.          col = 0;
  330.       }
  331.       pack1 = pack1->next;
  332.    }
  333.    if (col)
  334.       strout("\r\n");
  335.    return;
  336. }
  337.  
  338. void _pascal display_protos(void)
  339. {
  340.    int x,col;
  341.    struct proto_st *proto1;
  342.  
  343.    proto1 = PROTO_1;
  344.  
  345.    col = 0;
  346.    for (x = 0; x < totprotocols; x++) {
  347.       sprintf(temp,"[%d]%s",x +1,proto1->protoname);
  348.       while (strlen(temp) < 32) 
  349.          strcat(temp," ");
  350.       strout(temp);
  351.       if (col++) {
  352.          strout("\r\n");
  353.          col = 0;
  354.       }
  355.       proto1 = proto1->next;
  356.    }
  357.    if (col)
  358.       strout("\r\n");
  359.    return;
  360. }
  361.  
  362. /* Find the user in the config file */
  363.  
  364. int _pascal find_config(int handle,char *name,struct user_cfg *uscfg)
  365. {
  366.    int x,y;
  367.  
  368.    x = 0;
  369.    do_reset = FALSE;
  370.    lseek(handle,0L,SEEK_SET);        /* Rewind to begginning */
  371.    while (1) {
  372.       y = read(handle,(char *) uscfg,sizeof(struct user_cfg));
  373.       if( y < sizeof(struct user_cfg)) 
  374.          return(-1);
  375.       if (strcmpi(uscfg->name,name) == 0) { /* It's found! */
  376.          return(x);
  377.       }
  378.       x++;        /* Try next user */
  379.    }
  380. }
  381.  
  382. /* Find a blank slot in the config file */
  383.  
  384.  
  385. int _pascal find_blconfig(int handle)
  386. {
  387.    int x,y;
  388.  
  389.    x = 0;
  390.    lseek(handle,0L,SEEK_SET);        /* Rewind to begginning */
  391.    while (1) {
  392.       y = read(handle,(char *) &uscfg,sizeof(struct user_cfg));
  393.       if( y < sizeof(struct user_cfg)) 
  394.          return(-1);
  395.       if (uscfg.name[0] == 0)  /* It's found! */
  396.          return(x);
  397.       x++;        /* Try next user */
  398.    }
  399. }
  400.  
  401. int _pascal timeon(void)
  402. {
  403.    clock_t elapsed;
  404.    int t;
  405.  
  406.    elapsed = clock();
  407.    elapsed = startsecs - elapsed;
  408.    elapsed = elapsed / CLOCKS_PER_SEC;        /* Compute seconds */
  409.    t = (int) (elapsed / 60);
  410.    if (t < 0)
  411.       t = t * (-1);
  412.    return(t);
  413. }
  414.  
  415. void _pascal timeremain(void)
  416. {
  417.    int x;
  418.    char tstr[18];
  419.  
  420.    x = LastUser.timeremaining - timeon();        /* Fetch # of minutes on */
  421.    setcolor(TextAttr[TIME_LEFT]);
  422.    sprintf(tstr,"{%d min left} ",x);
  423.    strout(tstr);   
  424. }
  425.  
  426. struct proto_st * _pascal get_curprotolnk(void)
  427. {
  428.    int x;
  429.    struct proto_st *proto1;
  430.    struct proto_st *prev;
  431.  
  432.    proto1 = PROTO_1;        /* Point to first 1! */
  433.    for (x = 1; x < (int) USERCFG.protocol && proto1 != NULL; x++) {
  434.       prev = proto1;
  435.       proto1 = proto1->next;
  436.    }
  437.    if (proto1 == NULL) 
  438.       return(prev);
  439.    return(proto1);
  440. }
  441.  
  442. struct repupl_st * _pascal get_curreplnk(void)
  443. {
  444.    int x;
  445.    struct repupl_st *upl1;
  446.    struct repupl_st *prev;
  447.  
  448.    upl1 = REPUPL_1;        /* Point to first 1! */
  449.    for (x = 1; x < (int) USERCFG.protocol && upl1 != NULL; x++) {
  450.       prev = upl1;
  451.       upl1 = upl1->next;
  452.    }
  453.    if (upl1 == NULL) 
  454.       return(prev);
  455.    return(upl1);
  456. }
  457.  
  458. struct packer_st * _pascal get_curpacklnk(void)
  459. {
  460.    int x;
  461.    struct packer_st *pack1;
  462.    struct packer_st *prev;
  463.  
  464.    if (!USERCFG.packer)
  465.       return NULL;
  466.  
  467.    pack1 = PACKER_1;        /* Point to first 1! */
  468.    for (x = 1; x < (int) USERCFG.packer && pack1 != NULL; x++) {
  469.       prev = pack1;
  470.       pack1 = pack1->next;
  471.    }
  472.    if (pack1 == NULL) 
  473.       return(prev);
  474.    return(pack1);
  475. }
  476.  
  477. int _pascal get_kminute(void)
  478. {
  479.    int x,y;
  480.  
  481.    x = LastUser.flag / 10;         /* Compute cps */
  482.    y = LastUser.flag;
  483.    switch (LastUser.flag) {
  484.       case 300:
  485.          x -=  (x * 0.08f);        /* Slop off 8% */
  486.          break;
  487.  
  488.       case 1200:
  489.          x -=  (x * 0.18f);        /* Slop off 18% */
  490.          break;
  491.  
  492.       case 2400:
  493.          x -=  (x * 0.22f); 
  494.          break;
  495.  
  496.       case 4800:
  497.          x -=  (x * 0.25f); 
  498.          break;
  499.  
  500.       case 9600:
  501.          x -= (x * 0.28f);     
  502.          break;
  503.  
  504.       default:        /* Anything above 9600 baud */
  505.          x -= (x * 0.28f);     
  506.          break;
  507.    }
  508.    x *= 60;        /* Compute to minutes */
  509.    return x;
  510. }
  511.  
  512. /* The sysop menu */
  513. void _pascal Sys_menu(void)
  514. {
  515.    int x,choice,handl1,tuser;
  516.    char *p1;
  517.  
  518.    choice = TRUE;
  519.  
  520.    while (choice) {
  521.       setcolor(TextAttr[STD_TEXT]);
  522.       if (SysopMode) {
  523.          strout("\r\n\r\nLocal Sysop menu. Select a choice.\r\n");
  524.          strout("----------------------------------\r\n");
  525.       }
  526.       else {
  527.          strout("\r\n\r\nSysop menu. Select a choice.\r\n");
  528.          strout("----------------------------\r\n");
  529.       }
  530.       setcolor(TextAttr[MENU_KEY]);
  531.       strout("[D]elete a user          [E]rase user msg areas\r\n");
  532.       strout("[F]orce reconfig         [K]ill old users\r\n");
  533.       strout("[L]ist users             [V]iew user msg areas\r\n");
  534.       strout("[Q]uit\r\n");
  535.       if (!SysopMode) {
  536.          strout("\r\n");
  537.          timeremain();
  538.       }
  539.       else strout("[P]ack\r\n\r\n");
  540.       setcolor(TextAttr[PROMPT_TEXT]);
  541.       strout("Choice --> ");
  542.       x = chrin();
  543.       if (isalpha(x))
  544.          x &= 0x00df;
  545.       chrout((char) x);
  546.       strout("\r\n");
  547.       switch (x) {
  548.          case 'D':        /* Delete single users */
  549.             delete_users();
  550.             break;
  551.  
  552.          case 'E':        /* Erase user message areas */
  553.             if (test_task()) {
  554.                setcolor(TextAttr[ATTN_TEXT]);
  555.                strout("\r\nMaxMail is currently active in another partition. Try later.\r\n");
  556.                break;
  557.             }
  558.             setcolor(TextAttr[PROMPT_TEXT]);
  559.             strout("\r\nForce all users to re-do their msg area selection,\r\n");
  560.             strout("   or just single user? [a,s,Q] ");
  561.             x = chrin();
  562.             if (isalpha(x))
  563.                x &= 0xdf;
  564.             chrout((char) x);
  565.             strout("\r\n");
  566.             if(x == '\r')
  567.                x = 'Q';
  568.             if (x == 'A') {
  569.                if (!do_reset) {
  570.                   strout("Are you sure you want this? ");
  571.                   if (getyn(FALSE))
  572.                      do_reset = reset_config(USRCFG_MSGUPD);
  573.                }
  574.                else {
  575.                   setcolor(TextAttr[ATTN_TEXT]);
  576.                   strout("\r\nYou have already reset all the users during this session.\r\n");
  577.                }
  578.             }
  579.             else if(x == 'S'){        /* Single user reset */
  580.                strout("Enter user's name ---> ");
  581.                strin(temp);
  582.                if (!IsLocal)
  583.                   strout("\r\n");
  584.                p1 = strtok(temp,"\t\r\n");
  585.                if (p1) {
  586.                   handl1 = sopen(CfgFile,O_RDWR | O_BINARY | O_CREAT,SH_DENYNO,S_IREAD);
  587.                   if (handl1 == -1)
  588.                      aborterror(FILEOPEN,"Error opening User config file");
  589.                   tuser = find_config(handl1,p1,&uscfg);
  590.                   if (tuser < 0) {
  591.                      setcolor(TextAttr[ATTN_TEXT]);
  592.                      strout("Sorry but that user name does not exist.\r\n");
  593.                   }
  594.                   else {
  595.                      uscfg.flags |= USRCFG_MSGUPD;
  596.                      lseek(handl1,(long) (tuser * sizeof(struct user_cfg)),SEEK_SET);
  597.                      write(handl1,(struct user_cfg *) &uscfg,sizeof(struct user_cfg));
  598.                   }
  599.                   close(handl1);
  600.                }
  601.             }
  602.             break;
  603.  
  604.          case 'V':        /* List user message areas */
  605.             examine_user();
  606.             break;
  607.  
  608.          case 'F':        /* Force all users to re-do configuration */
  609.             if (test_task()) {
  610.                setcolor(TextAttr[ATTN_TEXT]);
  611.                strout("\r\nMaxMail is currently active in another partition. Try later.\r\n");
  612.                break;
  613.             }
  614.             setcolor(TextAttr[PROMPT_TEXT]);
  615.             strout("\r\nForce all users to re-do their configuration,\r\n");
  616.             strout("   or just single user? [a,s,Q] ");
  617.             x = chrin();
  618.             if (isalpha(x))
  619.                x &= 0xdf;
  620.             chrout((char) x);
  621.             strout("\r\n");
  622.             if(x == '\r')
  623.                x = 'Q';
  624.             if (x == 'A') {
  625.                if (!do_reset) {
  626.                   strout("Are you sure you want this? ");
  627.                   if (getyn(FALSE))
  628.                      do_reset = reset_config(USRCFG_FUPD);
  629.                }
  630.                else {
  631.                   setcolor(TextAttr[ATTN_TEXT]);
  632.                   strout("\r\nYou have already reset all the users during this session.\r\n");
  633.                }
  634.             }
  635.             else if(x == 'S'){        /* Single user reset */
  636.                strout("Enter user's name ---> ");
  637.                strin(temp);
  638.                if (!IsLocal)
  639.                   strout("\r\n");
  640.                p1 = strtok(temp,"\t\r\n");
  641.                if (p1) {
  642.                   handl1 = sopen(CfgFile,O_RDWR | O_BINARY | O_CREAT,SH_DENYNO,S_IREAD);
  643.                   if (handl1 == -1)
  644.                      aborterror(FILEOPEN,"Error opening User config file");
  645.                   tuser = find_config(handl1,p1,&uscfg);
  646.                   if (tuser < 0) {
  647.                      setcolor(TextAttr[ATTN_TEXT]);
  648.                      strout("Sorry but that user name does not exist.\r\n");
  649.                   }
  650.                   else {
  651.                      uscfg.flags |= USRCFG_FUPD;
  652.                      lseek(handl1,(long) (tuser * sizeof(struct user_cfg)),SEEK_SET);
  653.                      write(handl1,(struct user_cfg *) &uscfg,sizeof(struct user_cfg));
  654.                   }
  655.                   close(handl1);
  656.                }
  657.             }
  658.             break;
  659.  
  660.          case 'K':        /* Kill older users */
  661.             setcolor(TextAttr[PROMPT_TEXT]);
  662.             strout("\r\nThis will delete all MaxMail users who are no longer active on your bbs\r\n");
  663.             strout("Are you sure you want this? ");
  664.             if (getyn(FALSE))
  665.                kill_oldusers();
  666.             break;
  667.  
  668.          case 'L':        /* User stats */
  669.             user_stats();
  670.             break;
  671.  
  672.          case 'P':
  673.             if (SysopMode)
  674.                PackUsers();
  675.             break;
  676.  
  677.          case 'Q':        /* Quit */
  678.             choice = FALSE;
  679.             break;
  680.       }
  681.    }
  682.    strout("\r\n\r\n");
  683.    setcolor(TextAttr[STD_TEXT]);
  684.    return;
  685. }
  686.  
  687. /* Display selected message areas, if flag is TRUE, only areas
  688.     with new messages, else show ALL selected areas */
  689. void _pascal show_areas(int flag)
  690. {
  691.    int x,col,msgpos;
  692.    struct msgupd_st *msgupd;
  693.  
  694.    msgupd = MSGUPD_1;
  695.    setcolor(TextAttr[HILITE_TEXT]);
  696.    while (msgupd) {
  697.       msgpos = 0;
  698.       col = 0;
  699.       while (msgupd && msgpos < 20) {
  700.          fseek(afile,msgupd->areaindex,SEEK_SET);
  701.          fread(&AREA,astrlen,1,afile);
  702.          if ((flag && msgupd->msgcount) || !flag) {
  703.             setcolor(TextAttr[STD_TEXT]);
  704.             sprintf(temp,"[%03d]",msgupd->areano);
  705.             strout(temp);
  706.             setcolor(TextAttr[HILITE_TEXT]);
  707.             strncpy(temp1,AREA.msginfo,13);
  708.             temp1[13] = 0;
  709.             sprintf(temp," %s",temp1);
  710.             while (strlen(temp) <= 14) 
  711.                strcat(temp," ");
  712.             strout(temp);
  713.             if (msgupd->msgcount) {
  714.                sprintf(temp,"(%003u new msgs) ",msgupd->msgcount);
  715.                strout(temp);
  716.             }
  717.             else strout("(No new msgs)  ");
  718.       /* Build the flags display */
  719.             temp[0] = 0;
  720.             if (msgupd->attribute & ECHOMAIL)
  721.                strcat(temp,"E");
  722.             else if(msgupd->attribute & SYSMAIL)
  723.                strcat(temp,"S");
  724.             else strcat(temp,"L");
  725.             if (msgupd->flags & AREA_FORCED) 
  726.                strcat(temp,"*");        /* Forced area symbol */
  727.             while (strlen(temp) < 4)
  728.                strcat(temp," ");
  729.             setcolor(TextAttr[PROMPT_TEXT]);
  730.             strout(temp);
  731.             setcolor(TextAttr[HILITE_TEXT]);
  732.             if (col == 1) {
  733.                strout("\r\n");
  734.                col = 0;   
  735.             }
  736.             else col++;
  737.             msgpos++;
  738.          }
  739.          msgupd = msgupd->next;
  740.       }
  741.       if (msgupd) {
  742.          setcolor(TextAttr[STD_TEXT]);
  743.          strout("\r\nPress ESC to abort or any other key to continue");
  744.          x = chrin();
  745.          strout("\r\n");
  746.          if (x == 0x1b)
  747.             msgupd = NULL;
  748.       }
  749.    }
  750.    setcolor(TextAttr[STD_TEXT]);
  751.    if (col)
  752.       strout("\r\n");
  753. }
  754.  
  755. int _pascal is_selarea(int msgnum)
  756. {
  757.    struct msgupd_st *msgupd;
  758.    int x;
  759.  
  760.    msgupd = MSGUPD_1;
  761.    x = 1;
  762.    while (msgupd) {
  763.       if (msgupd->areano == (word) msgnum)
  764.          return x;        /* Return linked list number */
  765.       msgupd = msgupd->next;
  766.       x++;
  767.    }
  768.    return(FALSE);
  769. }
  770.  
  771. void _pascal update_msgs(void)
  772. {
  773.    struct msgupd_st *msgupd;
  774.    int x = FALSE;
  775.  
  776.    msgupd = MSGUPD_1;
  777.    while (msgupd) {
  778.       if (msgupd->update) {
  779.          msgupd->startmsg += msgupd->readmsgs;
  780.          adjust_lastread(msgupd->msgpath,msgupd->startmsg);
  781.          x = TRUE;
  782.       }
  783.       msgupd = msgupd->next;
  784.    }
  785.    if (x) {
  786.       setcolor(TextAttr[HILITE_TEXT]);
  787.       strout("\r\nYour lastread message pointers are now being updated\r\n");
  788.    }
  789. }
  790.  
  791. void _pascal adjust_lastread(char *msgpath,word num)
  792. {
  793.    char LastRdFile[65];
  794.    long pos;
  795.    int x;
  796.  
  797.    if (LastUser.lastread_ptr)
  798.       sprintf(LastRdFile,"%slastread.bbs",msgpath);
  799.    else sprintf(LastRdFile,"%slastread",msgpath);  
  800.    x = sopen(LastRdFile,O_RDWR | O_BINARY,SH_DENYNO,S_IWRITE);    /* Poke into the lastread file */
  801.    if (x >= 0) {        /* Is it there? */
  802.       pos = (long) (LastUser.lastread_ptr * sizeof(word));
  803.       if ((lseek(x,pos,SEEK_SET)) == pos) 
  804.          write(x,(word *) &num,sizeof(word));
  805.       close(x);
  806.    }
  807. }
  808.  
  809. word _pascal get_lastread(char *msgpath)
  810. {
  811.    char LastRdFile[65];
  812.    int x;
  813.    FILE *rdfile;
  814.    word num;
  815.    long pos;
  816.    struct stat fbuf;
  817.  
  818.    if (LastUser.lastread_ptr)        /* Is it the #0 user? */
  819.       sprintf(LastRdFile,"%slastread.bbs",msgpath);
  820.    else sprintf(LastRdFile,"%slastread",msgpath);  
  821.    x = sopen(LastRdFile,O_RDONLY | O_BINARY,SH_DENYNO,S_IREAD);    /* Poke into the lastread file */
  822.    if (x >= 0) {        /* Is it there? */
  823.       pos = (long) (LastUser.lastread_ptr * sizeof(word));
  824.       if ((lseek(x,pos,SEEK_SET)) == pos) {
  825.          read(x,(word *) &num,sizeof(word));
  826.          close(x);
  827.       }
  828.       else {        /* We need to append or create file */
  829.          close(x);        /* Re-open as hi level i/o, it's easier */
  830.          stat(LastRdFile,&fbuf);        /* We need size */
  831.          rdfile = _fsopen(LastRdFile,"ab+",SH_DENYNO);        /* Create */
  832.          if (rdfile != NULL) {        /* We have to append lastread file */
  833.             num = (word) (fbuf.st_size / sizeof(word));        /* How many ptrs so far? */
  834.             x = (int) LastUser.lastread_ptr - num;        /* How many to add */
  835.             num = 0;
  836.             while (x) {
  837.                fwrite((word *) &num,sizeof(word),1,rdfile);        /* Append as many as needed */
  838.                x--;
  839.             }
  840.             fclose(rdfile);
  841.          }
  842.          else num = 0;
  843.       }
  844.    }
  845.    else {        /* Create it then */
  846.       num = 0;
  847.       rdfile = _fsopen(LastRdFile,"wb+",SH_DENYNO);        /* Create */
  848.       if (rdfile != NULL) {        /* We may have to build lastread file */
  849.          if (LastUser.lastread_ptr) {        /* Not sysop */
  850.             x = LastUser.lastread_ptr;
  851.             while (x) {
  852.                fwrite((word *) &num,sizeof(word),1,rdfile);
  853.                x--;
  854.             }
  855.          }
  856.          else fwrite((word *) &num,sizeof(word),1,rdfile);
  857.          fclose(rdfile);
  858.       }
  859.    }
  860.    return num;
  861. }
  862.  
  863. struct msgupd_st * _pascal find_area(int msgnum)
  864. {
  865.    struct msgupd_st *msgst;
  866.  
  867.    msgst = MSGUPD_1;
  868.    while (msgst) {
  869.       if (msgst->areano == (word) msgnum)
  870.          break;
  871.       msgst = msgst->next;
  872.    }
  873.    return msgst;
  874. }
  875.  
  876. void _pascal delay_s(unsigned n)
  877. /* n = Number of seconds */
  878. {
  879.    n *= 1000;        /* Convert to seconds */
  880.    delay_ms(n);
  881. }
  882.  
  883. void _pascal delay_ms(unsigned n)
  884.  /* milleseconds to delay */
  885. {
  886.     struct timeb timebuf;
  887.     long end_time;
  888.     unsigned end_millitm;
  889.  
  890.     /* get current time and calculate ending time */
  891.     ftime(&timebuf);
  892.     end_time = timebuf.time + (n / 1000);
  893.     end_millitm = timebuf.millitm + (n % 1000);
  894.     if (end_millitm >= 1000) {
  895.         ++end_time;
  896.         end_millitm -= 1000;
  897.     }
  898.  
  899.     /* loop until ending time reached */
  900.     do ftime(&timebuf);
  901.     while (timebuf.time < end_time ||
  902.           (timebuf.time == end_time && timebuf.millitm < end_millitm));
  903. }
  904.  
  905. int _pascal find_realuser(char *name,int handle)
  906. {
  907.    int x;
  908.    struct _usr USER;
  909.  
  910.    lseek(handle,0L,SEEK_SET);
  911.    x = read(handle,(char *) &USER,user_slen);
  912.    while (x == user_slen) {
  913.       if (strcmpi(name,USER.name) == 0) {
  914.          if (USER.flag & UFLAG_deleted)
  915.             return(FALSE);        /* It's there but it is deleted! */
  916.          else return(TRUE);
  917.       }
  918.       x = read(handle,(char *) &USER,user_slen);
  919.    }
  920.    return(FALSE);        /* Couldn't find it */
  921. }
  922.  
  923. /* Test to see if this message area is a skip one, if so, return TRUE */
  924. int _pascal isskiparea(int msgarea)
  925. {
  926.    int x;
  927.  
  928.    if (LastUser.priv >= ASSTSYSOP || msgarea == 0)
  929.       return FALSE;    /* Sysops should always be able to get ALL areas */
  930.  
  931.    for (x = 0; x < SkipCount; x++) {
  932.       if(msgarea == *(SkipAreas[x]))
  933.          return TRUE;
  934.    }
  935.    return FALSE;
  936. }
  937.  
  938. /* Test to see if this message area is a forced one, if so, return TRUE */
  939. int _pascal isForcearea(int msgarea)
  940. {
  941.    int x;
  942.  
  943. /*   if (LastUser.priv >= ASSTSYSOP || msgarea == 0)
  944.       return FALSE; */     /* Sysops should'nt be forced */
  945.  
  946.    for (x = 0; x < ForceCount; x++) {
  947.       if(msgarea == *(ForceAreas[x]))
  948.          return TRUE;
  949.    }
  950.    return FALSE;
  951. }
  952.  
  953. void _pascal MarkForce(void)
  954. {
  955.    int x;
  956.    struct msgupd_st *new;
  957.    struct msgupd_st *msgupd;
  958.    struct msgupd_st *prev;
  959.  
  960.    for (x = 0; x < ForceCount; x++)  {
  961.       msgmark(*ForceAreas[x]);
  962.       msgupd = MSGUPD_1;
  963.       new = build1_area(*ForceAreas[x],FALSE);
  964.       if (new) {
  965.          USERCFG.totselareas++;
  966.          if (MSGUPD_1 == NULL) 
  967.             MSGUPD_1 = new;
  968.          else {        /* Attach it to the end */
  969.             prev = msgupd;
  970.             while (msgupd) {
  971.                prev = msgupd;
  972.                msgupd = msgupd->next;
  973.             }
  974.             prev->next = new;
  975.          }
  976.          new->next = NULL;
  977.          new->update = FALSE;
  978.       }
  979.    }
  980. }
  981.  
  982. void _pascal erase_arc()
  983. {
  984.    struct   find_t c_file;
  985.    char tname[13];
  986.    struct msgupd_st *msgupd;
  987.  
  988.  
  989.    tempdir();
  990.    
  991.  
  992.    if (QWKDir[0]) 
  993.       chdir("..");
  994.  
  995.    unlink(ArcFile);
  996.    unlink(StatName);
  997.    unlink(TxtFile);
  998.  
  999.    if (QWKDir[0]) 
  1000.       chdir(QWKDir);
  1001.  
  1002.    if (USERCFG.msgfrmt == 1) {
  1003.       if (_dos_findfirst("*.ndx",_A_NORMAL,&c_file) == 0) {
  1004.          unlink(c_file.name);
  1005.          while (_dos_findnext(&c_file) == 0)
  1006.             unlink(c_file.name);
  1007.       }
  1008.       unlink(ArcFile);
  1009.       unlink("Messages.dat");
  1010.       unlink("Control.dat");
  1011.       unlink("NewFiles.dat");
  1012.       sprintf(tname,"%s.rep",BBSid);
  1013.       unlink(tname);
  1014.    }
  1015.  
  1016.    msgupd = MSGUPD_1;
  1017.    while (msgupd) {        /* Remove update flag */
  1018.       msgupd->update = FALSE;
  1019.       msgupd = msgupd->next;
  1020.    }
  1021.  
  1022. /* Force arc recreation */
  1023.    PackDone = FALSE;
  1024.    FirstArc = -1;
  1025.    homedir();
  1026. }
  1027.  
  1028. /* Strip leading and trailing whitespace */
  1029. char * _pascal stripwhite(char *strng)
  1030. {
  1031.    char *p,*pp;
  1032.  
  1033.    while (*strng && isspace(*strng)) {        /* Trim leading space */
  1034.       pp = strng;
  1035.       p = strng + 1;
  1036.       while (*pp) {        /* Shift up characters */
  1037.          *pp = *p;
  1038.          p++;
  1039.          pp++;
  1040.       }
  1041.    }
  1042.  
  1043.    if (!*strng)        /* We have reached end of string */
  1044.       return(NULL);
  1045.  
  1046.    p = strng + (strlen(strng) - 1);        /* Point to tail */
  1047.    while (isspace(*p)) 
  1048.       p--;
  1049.    p[1] = 0;        /* Terminate at start of trailing space */
  1050.    return(strng);
  1051. }
  1052.  
  1053. /* Turn on given color attribute for video */
  1054. void _pascal setcolor(int color)
  1055. {
  1056.    byte back,fore;
  1057.    byte bit2,bit0;
  1058.    char attstr[20];
  1059.  
  1060.    fore = (byte) (color & 0x000f);
  1061.    back = (byte) (color & 0x00070);
  1062.    back = (byte) (back >> 4);
  1063.    sprintf(attstr,"\x1b[1;%d;%dm",back+40,fore+30);
  1064.  
  1065.    if (LastUser.ansi) {
  1066.       printf("\x1b[0m");        /* Reset attributes */
  1067.       FossSendStr("\x1b[0m");        /* Reset attributes */
  1068.       if (color & 0x0080) {        /* Test blink bit */
  1069.          printf("\x1b[5m");
  1070.          FossSendStr("\x1b[5m");
  1071.       }
  1072.       printf(attstr);
  1073.       FossSendStr(attstr);
  1074.    }
  1075.  
  1076.    else if (LastUser.avatar) {
  1077.       color |= 0x8;        /* Turn on intensity for foreground */
  1078.       printf(attstr); /* Print ANSI instead of avatar to local console */
  1079.  
  1080. /* Reverse bits 2 and 0 */
  1081.       bit2 = (byte) (color & 0x04);
  1082.       bit0 = (byte) (color & 0x01);
  1083.       color &= 0xfa;        /* Turn off bit 0 and bit 2 */
  1084.       color |= (bit0 << 2);
  1085.       color |= (bit2 >> 2);
  1086.  
  1087.       sprintf(attstr,"\x16\x01%c",color);
  1088.       FossSendStr(attstr);        /* Send out attribute byte */
  1089.    }
  1090.  
  1091.    CurColor = color;
  1092.    if ((word) color == TextAttr[ATTN_TEXT]) {
  1093.       FossSendStr("\07");
  1094.       if (IsLocal)
  1095.          printf("\07");
  1096.    }
  1097. }
  1098.  
  1099. /* Initiate chat mode with user */
  1100. void _pascal chat(void)
  1101. {
  1102.    unsigned ch;
  1103.    int key,col;
  1104.    int minutes;
  1105.  
  1106. /*   if (IsLocal)
  1107.       return; */        /* Makes no sense to chat with yourself! */
  1108.  
  1109.    logit("Sysop <-> User in chat mode",'#');
  1110.  
  1111.    setcolor(TextAttr[HILITE_TEXT]);
  1112.    strout("\r\n\r\nCHAT MODE: \r\n");
  1113.    col = 0;
  1114.    while (1) {
  1115.       minutes = timeon();        /* Establish a counter */
  1116.       while ((ch = FossGetCh()) == 0xFFFF) {
  1117.          check_carrier();
  1118.          if (timeon() > minutes + IDLETIME) {        /* User is idle too long */
  1119.             aborterror(USERIDLE,NULL);
  1120.          }
  1121.       }
  1122.       minutes = 0;        /* Reset idle time! */
  1123.       key = ch & 0xff;
  1124.       if (key == '\r') {        /* Carraige return */
  1125.          col = 0;
  1126.          chrout('\n');
  1127.       }
  1128.       else if (key == '\b') {        /* Backspace */
  1129.          chrout((char) key);
  1130.          chrout(' ');
  1131.          chrout((char) key);
  1132.       }
  1133.       else if (key == '\x1b')        /* Escape */
  1134.          break;
  1135.       else {
  1136.          chrout((char) key);
  1137.          col++;
  1138.          if (col >= 79) {        /* Crude word wrap */
  1139.             col = 0;
  1140.             chrout('\n');
  1141.          }
  1142.       }
  1143.    }
  1144.    logit("Chat end",'#');
  1145.    strout("\r\n\r\nEND CHAT:\r\n");
  1146. }
  1147.  
  1148. void _pascal Holler(void)
  1149. {
  1150.    int x;
  1151.    unsigned ch;
  1152.  
  1153.    if (Hollercount >= 3) {
  1154.       setcolor(TextAttr[ATTN_TEXT]);
  1155.       strout("\r\nYou have already hollered for the sysop 3 times.\r\n");
  1156.       return;
  1157.    }
  1158.    if (!Hollercount)        /* First time */
  1159.       logit("User is hollering for sysop",'#');
  1160.    setcolor(TextAttr[HILITE_TEXT]);
  1161.    strout("\r\nHollering for sysop. Press ESC to abort.....\r\n");
  1162.    setcolor(TextAttr[MENU_KEY]);
  1163.    printf("(SYSOP) Press ALT-C to start chat\r\n"); /* Show on local console */
  1164.    setcolor(TextAttr[HILITE_TEXT]);
  1165.    for (x=0; x < Bells; x++) {
  1166.       if (!IsLocal) {
  1167.          FossSendCh(0x07);
  1168.          FossSendCh(0x07);
  1169.          FossSendCh(0x07);
  1170.          FossSendCh(0x07);
  1171.       }
  1172.       tone(650,100);        /* Send bell to local console */
  1173.       tone(450,100);
  1174.       ch = FossGetCh();
  1175.       if (ch != 0xffff) {
  1176.          if (ch == 0x2e00) {
  1177.             chat();
  1178.             Hollercount = -1;
  1179.             break;
  1180.          }
  1181.          if ((ch & 0x00ff) == 0x1b)        /* Escape */
  1182.             break;
  1183.       }
  1184.       delay_ms(500);        /* Delay 1/2 second */
  1185.    }
  1186.    Hollercount++;
  1187. }
  1188.  
  1189. void _pascal PackUsers(void)
  1190. {
  1191.    int handl1,handl2,y;
  1192.    int old,new;
  1193.    char drive[_MAX_DRIVE];
  1194.    char dir[_MAX_DIR];
  1195.    char fname[_MAX_FNAME];
  1196.    char tname[_MAX_PATH];
  1197.  
  1198.    handl1 = sopen(CfgFile,O_RDWR | O_BINARY,SH_DENYRW,S_IREAD);
  1199.    if (handl1 == -1) {
  1200.       setcolor(TextAttr[ATTN_TEXT]);
  1201.       strout("\r\nCan't open user file");
  1202.       aborterror(FILEOPEN,"Error opening User config file");
  1203.    }
  1204.  
  1205.    _splitpath(CfgFile,drive,dir,fname,temp);
  1206.    sprintf(tname,"%s%s%s.$$$",drive,dir,fname);
  1207.  
  1208.    handl2 = sopen(tname,O_CREAT | O_RDWR | O_BINARY,SH_DENYWR,S_IWRITE);
  1209.    if (handl2 == -1) {
  1210.       close(handl1);
  1211.       setcolor(TextAttr[ATTN_TEXT]);
  1212.       strout("\r\nCan't open temp file");
  1213.       aborterror(FILEOPEN,"Error opening temp User config file");
  1214.    }
  1215.  
  1216.    old = new = 0;
  1217.    y = read(handl1,(char *) &uscfg,sizeof(struct user_cfg));
  1218.    while (y == sizeof(struct user_cfg)) {
  1219.       old++;
  1220.       if (uscfg.name[0]) { /* Write only the current ones */
  1221.          write(handl2,(char *) &uscfg,sizeof(struct user_cfg));
  1222.          new++;
  1223.          strout("*");
  1224.       }
  1225.       else strout(".");
  1226.       y = read(handl1,(char *) &uscfg,sizeof(struct user_cfg));
  1227.    }
  1228.    strout("\r\n");
  1229.    close(handl1);
  1230.    close(handl2);
  1231.    if (new != old) {
  1232.       setcolor(TextAttr[HILITE_TEXT]);
  1233.       sprintf(temp1,"%d empty records of %d total records were deleted.\r\n",old - new,old);
  1234.       strout(temp1);
  1235.       sprintf(tname,"%s%s%s.bak",drive,dir,fname);
  1236.       unlink(tname);        /* Remove older backup */
  1237.       if(!rename(CfgFile,tname))    {    /* Move current file to backup */
  1238.          sprintf(temp1,"\r\nCreating MaxMail user backup file %s\r\n",tname);
  1239.          strout(temp1);
  1240.          sprintf(tname,"%s%s%s.$$$",drive,dir,fname);
  1241.          rename(tname,CfgFile);     /* Rename new file */
  1242.       }
  1243.       else {
  1244.          sprintf(tname,"%s%s%s.$$$",drive,dir,fname);
  1245.          unlink(tname);        /* Remove this new version */
  1246.       }
  1247.    }
  1248.    else unlink(tname);        /* Delete temp file then */
  1249. }
  1250.  
  1251.  
  1252. /* Create a left justified string (NOT null terminated!) padded with blanks */
  1253. void _pascal ljstring(char *dest,char *src,int len)
  1254. {
  1255.    int x;
  1256.    char *p;
  1257.  
  1258.    strncpy(dest,src,len);
  1259.    x = strlen(dest);
  1260.    p = dest + x;
  1261.    while (x < len) {
  1262.       *p = ' ';
  1263.       p++;
  1264.       x++;
  1265.    }
  1266. }
  1267.  
  1268. int _pascal copy2temp(char *src)
  1269. {
  1270.    char fname[_MAX_FNAME];
  1271.    char fext[_MAX_EXT];
  1272.    char tname[_MAX_PATH];
  1273.  
  1274.    _splitpath(src,tname,tname,fname,fext);
  1275.  
  1276.    if (tdir[0])
  1277.       sprintf(tname,"%s\\",tdir);
  1278.  
  1279.    if (QWKDir[0]) {
  1280.       strcat(tname,QWKDir);
  1281.       strcat(tname,"\\");
  1282.    }
  1283.    strcat(tname,fname);
  1284.    strcat(tname,fext);        /* Now we have fule destname */
  1285.    return(copyfile(src,tname));
  1286.  
  1287. }
  1288.  
  1289. int _pascal copyfile(char *srcname, char *destname)
  1290. {
  1291.    int src,dest;
  1292.    unsigned size,tt;
  1293.    char _far *buff;
  1294.  
  1295.    dest = sopen(destname,O_CREAT | O_TRUNC | O_BINARY | O_RDWR,SH_DENYNO,S_IWRITE);
  1296.    if (dest < 0)
  1297.       return -1;
  1298.  
  1299.    src = sopen(srcname,O_BINARY | O_RDWR,SH_DENYNO,S_IREAD);
  1300.    if (src < 0) {
  1301.       close(dest);
  1302.       unlink(destname);        /* Remove it */
  1303.       return -1;
  1304.    }
  1305.  
  1306.    buff = (char _far *) _fmalloc((1024 * 10) + 5);
  1307.    if (buff == NULL)
  1308.       aborterror(BADALLOC,NULL);
  1309.  
  1310.    _dos_read(src,buff,1024 * 10,&size);
  1311.    while (size) {
  1312.       if(_dos_write(dest,buff,size,&tt))
  1313.          break;
  1314.       if(_dos_read(src,buff,1024 * 10,&size))
  1315.          break;
  1316.    }
  1317.    close(dest);
  1318.    close(src);
  1319.    _ffree(buff);
  1320.    return 0;
  1321. }
  1322.  
  1323. /* Move to our home directory */
  1324. void _pascal homedir(void)
  1325. {
  1326.    if (QWKDir[0])
  1327.       chdir("..");
  1328.  
  1329.    if (tdir[0])
  1330.       switch_dir(PRM(sys_path));
  1331.  
  1332. }
  1333.  
  1334. /* Switch to tempdir if used */
  1335. void _pascal tempdir(void)
  1336. {
  1337.    if (tdir[0])
  1338.       switch_dir(tdir);
  1339.  
  1340.    if (QWKDir[0])
  1341.       if(chdir(QWKDir) != 0)
  1342.          QWKDir[0] = 0;
  1343. }
  1344.  
  1345.